perm filename REDCOM.RED[CMP,LSP] blob
sn#330479 filedate 1978-01-24 generic text, type T, neo UTF8
%*********************************************************************
%*********************************************************************
% THE STANDARD LISP COMPILER
%********************************************************************;
%********************************************************************;
COMMENT machine dependent parts are in a separate file;
COMMENT these include the macros described below and, in addition,
an auxiliary function !&MKFUNC which is required to pass
functional arguments (input as FUNCTION <func>) to the
loader. In most cases, !&MKFUNC may be defined as MKQUOTE;
COMMENT general functions used in this compiler;
SYMBOLIC PROCEDURE EQCAR(U,V);
NOT ATOM U AND CAR U EQ V;
SYMBOLIC PROCEDURE LPRIE U;
<<PRINT("******" . U); ERROR(99,NIL)>>;
SYMBOLIC PROCEDURE MKQUOTE U;
LIST('QUOTE,U);
SYMBOLIC PROCEDURE REVERSIP U;
BEGIN SCALAR X,Y;
WHILE U DO <<X := CDR U; Y := RPLACD(U,Y); U := X>>;
RETURN Y
END;
SYMBOLIC PROCEDURE RPLACW(A,B);
RPLACA(RPLACD(A,CDR B),CAR B);
COMMENT the following two functions are used by the CONS open
coding. They should be defined in the interpreter if
possible. They should only be compiled without a COMPFN
for CONS;
SYMBOLIC PROCEDURE NCONS U; U . NIL;
SYMBOLIC PROCEDURE XCONS(U,V); V . U;
COMMENT Registers used:
1-MAXNARGS used for args of link. result returned in reg 1;
COMMENT Macros used in this compiler;
COMMENT The following macros must NOT change regs 1-MAXNARGS:
!*ALLOC nw allocate new stack frame of nw words
!*DEALLOC nw deallocate above frame
!*ENTRY name type noargs entry point to function name of type type
with noargs args
!*FREERSTR alst unbind free variables in alst
!*JUMP adr unconditional jump
!*JUMPNIL adr jump on register 1 NIL
!*JUMPT adr jump on register 1 not NIL
!*JUMPE adr exp jump on register 1 equal to exp
!*JUMPN adr exp jump on register 1 not equal to exp
!*LBL adr define label
!*LAMBIND regs alst bind free lambda vars in alst currently in regs
!*PROGBIND alst bind free prog vars in alst
!*RETURN return to previously saved return address
!*STORE reg floc store contents of reg (or NIL) in floc
COMMENT the following macro must only change specific register being
loaded:
!*LOAD reg exp load exp into reg;
COMMENT the following macros do not protect regs 1-MAXNARGS:
!*LINK fn nargs link to fn with nargs args
!*LINKL fn nargs loc load loc in reg 1, link to fn with nargs args
!*LINKR fn nargs nw link to fn with nargs args and return
removing frame of nw words;
COMMENT variable types are:
LOCAL allocated on stack and known only locally
GLOBAL accessed via cell (GLOBAL name) known to
loader at load time
FLUID accessed via cell (FLUID name)
known to loader. This cell is rebound by LAMBIND/
PROGBIND if variable used in lambda/prog list
and restored by FREERSTR;
COMMENT global flags used in this compiler:
!*MODULE indicates block compilation (a future extension of
this compiler)
!*NOLINKL if ON inhibits use of !*LINKL macro
!*NOLINKR if ON inhibits use of !*LINKR macro
!*ORD if ON forces left-to-right argument evaluation
!*PLAP if ON causes LAP output to be printed
!*R2I if ON causes recursion removal where possible
!*SAVEDEF if ON causes old (uncompiled) definition to remain
and saves compiled macros with indicator COMPEXP;
GLOBAL '(!*MODULE !*NOLINKL !*NOLINKR !*ORD !*PLAP !*R2I !*SAVEDEF);
COMMENT global variables used:
MAXNARGS number of arguments in true registers;
GLOBAL '(MAXNARGS);
COMMENT fluid variables used:
ALSTS alist of fluid parameters
FLAGG used in COMTST, and in FIXUP2
FREELST list of free variables with bindings
GOLIST storage map for jump labels
IREGS initial register contents
CODELIST code being built
CONDTAIL simulated stack of position in the tail of a COND
LLNGTH cell whose CAR is length of frame
NAME name of function being currently compiled
NARG number of arguments in function
REGS known current contents of registers as an alist with elements
of form (<reg> . <contents>)
RETN label for RETURN jump
LBLIST list of label words
JMPLIST list of locations in CODELIST of transfers
SLST association list for stores which have not yet been used
STLST list of active stores in function
STOMAP storage map for variables
SWITCH boolean expression value flag - keeps track of NULLs;
FLUID '(ALSTS FLAGG NAME GOLIST IREGS CODELIST CONDTAIL
LLNGTH NARG REGS RETN LBLIST JMPLIST SLST STLST STOMAP
SWITCH REGS1 IREGS1 FREELST);
SYMBOLIC PROCEDURE COMPILE X;
BEGIN SCALAR EXP,NAME;
WHILE X DO
<<NAME := CAR X;
EXP := GETD NAME;
IF NULL EXP THEN LPRIM LIST(NAME,'UNDEFINED)
ELSE COMPD(NAME,CAR EXP,CDR EXP);
X := CDR X>>
END;
SYMBOLIC PROCEDURE COMPD(NAME,TYPE,EXP);
BEGIN SCALAR CTYPE;
IF TYPE EQ 'EXPR THEN CTYPE := 'SUBR
ELSE IF TYPE EQ 'FEXPR THEN CTYPE := 'FSUBR
ELSE <<LPRIM LIST("UNCOMPILABLE FUNCTION TYPE",TYPE);
RETURN NIL>>;
IF NOT ATOM EXP
THEN IF !*MODULE THEN MODCMP(NAME,TYPE,EXP)
ELSE IF DFPRINT!*
THEN APPLY(DFPRINT!*,
LIST LIST(IF TYPE EQ 'EXPR THEN 'DE ELSE 'DF,
NAME,CADR EXP,CADDR EXP))
ELSE BEGIN SCALAR X;
X := LIST('!*ENTRY,NAME,CTYPE,LENGTH CADR EXP) .
!&COMPROC(EXP,NAME);
IF !*PLAP THEN FOR EACH Y IN X DO PRINT Y;
IF !*SAVEDEF THEN PUT(NAME,'COMPEXP,TYPE . X)
ELSE <<REMD NAME; LAP X>>
END;
RETURN NAME
END;
SYMBOLIC PROCEDURE !&COMPROC(EXP,NAME);
%compiles a function body, returning the generated LAP;
BEGIN SCALAR CODELIST,FLAGG,IREGS,IREGS1,JMPLIST,LBLIST,LLNGTH,
REGS,REGS1,ALSTS,RETN,SLST,STLST,STOMAP,CONDTAIL;
SCALAR REGS1,IREGS1,FREELST;
INTEGER NARG;
LLNGTH := LIST 0;
NARG := 0;
RETN := !&GENLBL();
STOMAP := '((NIL 0));
CODELIST := LIST ('!*ALLOC . LLNGTH);
EXP := !&PA1(EXP,NIL);
FOR EACH Z IN CADR EXP DO
<<!&FRAME Z;
NARG := NARG+1;
IF NOT NONLOCAL Z
THEN IREGS := NCONC(IREGS,LIST LIST(NARG,Z));
REGS := NCONC(REGS,LIST LIST(NARG,Z))>>;
IF NULL REGS THEN REGS := LIST(1 . NIL);
ALSTS := !&FREEBIND(CADR EXP,T);
!&COMVAL(CADDR EXP,0);
!&FREERSTR(ALSTS,0);
RETURN !&FIXUPS()
END;
SYMBOLIC PROCEDURE NONLOCAL X;
IF FLUIDP X THEN 'FLUID
ELSE IF GLOBALP X THEN 'GLOBAL
ELSE NIL;
FLUID '(VARS);
SYMBOLIC PROCEDURE !&PA1(U,VARS);
BEGIN SCALAR X;
RETURN
IF ATOM U THEN IF CONSTANTP U OR U MEMQ '(NIL T)
THEN MKQUOTE U
ELSE IF U MEMBER VARS THEN U
ELSE IF GLOBALP U OR FLUIDP U THEN U
ELSE <<MKNONLOCAL U; U>>
ELSE IF NOT ATOM CAR U THEN !&PA1(CAR U,VARS) . !&PALIS(CDR U,VARS)
ELSE IF (X := GET(CAR U,'MACRO)) AND NOT GET(CAR U,'COMPFN)
THEN !&PA1(APPLY(X,LIST U),VARS)
ELSE IF CAR U EQ 'NOT THEN !&PA1('NULL . CDR U,VARS)
ELSE IF CAR U EQ 'COND
THEN 'COND .
FOR EACH Z IN CDR U
COLLECT LIST(!&PA1(CAR Z,VARS),!&PA1(CADR Z,VARS))
ELSE IF CAR U MEMBER '(GO QUOTE) THEN U
ELSE IF CAR U EQ 'LAMBDA
THEN 'LAMBDA . CADR U . !&PALIS(CDDR U,APPEND(CADR U,VARS))
ELSE IF CAR U EQ 'FUNCTION THEN IF ATOM CADR U THEN MKQUOTE CADR U
ELSE MKQUOTE COMPD(!&MKNAM NAME,'EXPR,CADR U)
ELSE IF X := GET(CAR U,'PA1FN) THEN APPLY(X,LIST(U,VARS))
ELSE IF CAR U EQ 'PROG
THEN 'PROG . CADR U . !&PAPROG(CDDR U,APPEND(CADR U,VARS))
ELSE IF (X := GETD CAR U) AND CAR X MEMQ '(FEXPR FSUBR)
AND NOT GET(CAR U,'COMPFN)
THEN <<!&PALIS(CDR U,NIL); %to check for fluid vars;
LIST(CAR U,MKQUOTE CDR U)>>
ELSE CAR U . !&PALIS(CDR U,VARS)
END;
SYMBOLIC PROCEDURE !&PALIS(U,VARS);
FOR EACH X IN U COLLECT !&PA1(X,VARS);
SYMBOLIC PROCEDURE !&PAPROG(U,VARS);
FOR EACH X IN U COLLECT IF ATOM X THEN X ELSE !&PA1(X,VARS);
SYMBOLIC PROCEDURE MKNONLOCAL U;
%make an undeclared non-local variable FLUID;
<<LPRIM LIST(U,"declared fluid"); FLUID LIST U; LIST('FLUID,U)>>;
SYMBOLIC PROCEDURE !&MKNAM U;
%generates unique name for auxiliary function in U;
COMPRESS APPEND(EXPLODE U,EXPLODE GENSYM());
UNFLUID '(VARS);
SYMBOLIC PROCEDURE !&COMVAL(EXP,STATUS);
%computes code for value of EXP;
IF !&ANYREG(EXP,NIL) THEN IF STATUS>1 THEN NIL
ELSE !&LREG1(EXP,STATUS)
ELSE !&COMVAL1(EXP,STOMAP,STATUS);
SYMBOLIC PROCEDURE !&COMVAL1(EXP,STOMAP,STATUS);
BEGIN SCALAR X;
IF ATOM EXP THEN IF STATUS<2 THEN !&LREG1(EXP,STATUS) ELSE NIL
ELSE IF NOT ATOM CAR EXP
THEN IF CAAR EXP EQ 'LAMBDA
THEN !&COMPLY(CAR EXP,CDR EXP,STATUS)
ELSE !&COMAPPLY(LIST('APPLY,CAR EXP,!&PALIST CDR EXP),
STATUS)
ELSE IF X := GET(CAR EXP,'COMPFN) THEN APPLY(X,LIST(EXP,STATUS))
ELSE IF ATSOC(CAR EXP,STOMAP)
THEN !&COMAPPLY(LIST('APPLY,CAR EXP,!&PALIST CDR EXP),STATUS)
ELSE IF !*R2I AND CAR EXP EQ NAME AND STATUS=0 AND NULL FREELST
THEN !&COMREC(EXP,STATUS)
ELSE !&CALL(CAR EXP,!&COMLIS CDR EXP,STATUS);
RETURN NIL
END;
SYMBOLIC PROCEDURE !&ANYREG(U,V);
%determines if U can be loaded in any register;
%!*ORD = T means force correct order, unless safe;
NOT ATOM U AND CAR U EQ 'QUOTE
OR ((IF ATOM U
THEN NOT NONLOCAL U AND ATSOC(U,STOMAP)
OR !&ANYREGL V
ELSE GET(CAR U,'ANYREG) AND !&ANYREG(CADR U,NIL))
AND (NULL !*ORD OR !&ANYREGL V));
SYMBOLIC PROCEDURE !&ANYREGL U;
NULL U OR !&ANYREG(CAR U,NIL) AND !&ANYREGL CDR U;
SYMBOLIC PROCEDURE !&CALL(FN,ARGS,STATUS);
%ARGS is reversed list of compiled arguments of FN;
BEGIN INTEGER ARGNO;
ARGNO := LENGTH ARGS;
!&LOADARGS(ARGS,STATUS);
IF NOT !*NOLINKL AND CAAR CODELIST EQ '!*LOAD
AND CADAR CODELIST=1
AND NUMBERP CADDAR CODELIST
AND CADDAR CODELIST<=MAXNARGS
THEN <<!&ATTACH('!*LINKL . FN . ARGNO . CDDAR CODELIST);
!&MOVEUP CDR CODELIST>>
ELSE !&ATTACH LIST('!*LINK,FN,ARGNO);
REGS := LIST (1 . NIL)
END;
SYMBOLIC PROCEDURE !&COMLIS EXP;
%returns reversed list of compiled arguments;
BEGIN SCALAR ACUSED,Y;
WHILE EXP DO
<<IF !&ANYREG(CAR EXP,CDR EXP) THEN Y := CAR EXP . Y
ELSE <<IF ACUSED THEN !&STORE1();
!&COMVAL1(CAR EXP,STOMAP,1);
ACUSED := GENSYM();
REGS := (1 . ACUSED . CDAR REGS) . CDR REGS;
Y:=ACUSED . Y>>;
EXP := CDR EXP>>;
RETURN Y
END;
SYMBOLIC PROCEDURE !&STORE1();
%Marks contents of register 1 for storage;
BEGIN SCALAR X;
X := CADAR REGS;
IF NULL X OR EQCAR(X,'QUOTE) THEN RETURN NIL
ELSE IF NOT ATSOC(X,STOMAP) THEN !&FRAME X;
!&STORE(X,1)
END;
SYMBOLIC PROCEDURE !&COMPLY(FN,ARGS,STATUS);
BEGIN SCALAR ALSTS,VARS; INTEGER N,I;
VARS := CADR FN;
ARGS := !&COMLIS ARGS;
N := LENGTH ARGS;
IF N>MAXNARGS THEN LPRIE LIST("TOO MANY LAMBDA ARGS IN ",NAME);
!&LOADARGS(ARGS,1);
ARGS:=!&REMVARL VARS; % The stores that were protected;
I:=1;
FOR EACH V IN VARS DO <<!&FRAME V;
REGS:=!&REPASC(I,V,REGS);
I:=I+1>>;
ALSTS := !&FREEBIND(VARS,T); %Old fluid values saved;
I:=1;
FOR EACH V IN VARS DO
<<IF NOT NONLOCAL V THEN !&STORE(V,I);
I:=I+1>>;
!&COMVAL(CADDR FN,STATUS);
!&FREERSTR(ALSTS,STATUS);
% Should now REMVAR names again, ? BEFORE OR AFTER ? ;
!&RSTVARL(VARS,ARGS)
END;
SYMBOLIC PROCEDURE !&COMREC(EXP,STATUS);
BEGIN SCALAR X,Z;
!&LOADARGS(!&COMLIS CDR EXP,STATUS);
Z := CODELIST;
WHILE CDDR Z DO Z := CDR Z;
IF CAAR Z EQ '!*LBL THEN X := CDAR Z
ELSE <<X := !&GENLBL();
RPLACD(Z,LIST(('!*LBL . X),CADR Z))>>;
!&ATTJMP X
END;
SYMBOLIC PROCEDURE !&LOADARGS(ARGS,STATUS);
BEGIN INTEGER N;
N := LENGTH ARGS;
IF N>MAXNARGS THEN LPRIE LIST("TOO MANY ARGUMENTS IN",NAME);
IF STATUS>0 THEN !&CLRREGS();
WHILE ARGS DO
<<!&LREG(N,CAR ARGS,CDR ARGS,STATUS);
N := N-1; ARGS := CDR ARGS>>;
END;
SYMBOLIC PROCEDURE !&LOCATE X;
BEGIN SCALAR Y,VTYPE;
IF EQCAR(X,'QUOTE) THEN RETURN LIST X
ELSE IF Y := !&RASSOC(X,REGS)
THEN RETURN LIST LIST('!*REG,CAR Y)
ELSE IF NOT ATOM X THEN RETURN LIST(CAR X . !&LOCATE CADR X)
ELSE IF (VTYPE := NONLOCAL X) THEN RETURN LIST LIST(VTYPE,X);
WHILE Y := ATSOC(X,SLST) DO SLST := DELETE(Y,SLST);
RETURN IF Y := ATSOC(X,STOMAP) THEN CDR Y
ELSE LIST MKNONLOCAL X
END;
SYMBOLIC PROCEDURE !&LREG(REG,U,V,STATUS);
BEGIN SCALAR X,Y;
IF (X := ASSOC(REG,REGS)) AND U MEMBER CDR X THEN RETURN NIL
ELSE IF (Y := ASSOC(REG,IREGS))
AND (STATUS>0 OR !&MEMLIS(CADR Y,V))
THEN <<!&STORE(CADR Y,REG); IREGS := DELETE(Y,IREGS)>>;
!&ATTACH ('!*LOAD . REG . !&LOCATE U);
REGS := !&REPASC(REG,U,REGS)
END;
SYMBOLIC PROCEDURE !&LREG1(X,STATUS);
!&LREG(1,X,NIL,STATUS);
SYMBOLIC PROCEDURE !&PALIST U;
'LIST . U;
COMMENT Functions for Handling Non-local Variables;
SYMBOLIC PROCEDURE !&FREEBIND(VARS,LAMBP);
%bind FLUID variables in lambda or prog lists;
%LAMBP is true for LAMBDA, false for PROG;
BEGIN SCALAR FALST,FREGS,X,Y; INTEGER I;
I := 1;
FOR EACH X IN VARS DO
<<IF FLUIDP X
THEN <<FALST := (X . !&GETFFRM X) . FALST;
FREGS := I . FREGS>>
ELSE IF GLOBALP X
THEN LPRIE LIST("CANNOT BIND GLOBAL ",X);
I := I+1>>;
IF NULL FALST THEN RETURN NIL;
IF LAMBP THEN !&ATTACH LIST('!*LAMBIND,FREGS,FALST)
ELSE !&ATTACH LIST('!*PROGBIND,FALST);
RETURN FALST
END;
SYMBOLIC PROCEDURE !&FREERSTR(ALSTS,STATUS);
%restores FLUID variables;
IF ALSTS THEN !&ATTACH LIST('!*FREERSTR,ALSTS);
SYMBOLIC PROCEDURE !&ATTACH U;
CODELIST := U . CODELIST;
SYMBOLIC PROCEDURE !&STORE(U,REG);
%marks expression U in register REG for storage;
BEGIN SCALAR X;
X := '!*STORE . REG . !&GETFRM U;
STLST := X . STLST;
!&ATTACH X;
IF NULL CONDTAIL AND (X := ATSOC(U,SLST))
THEN <<STLST := !&DELEQ(CADR X,STLST);
SLST := !&DELEQ(X,SLST);
RPLACA(CADR X,'!*NOOP)>>;
IF ATOM U THEN SLST := (U . CODELIST) . SLST
END;
COMMENT Functions for general tests;
SYMBOLIC PROCEDURE !&COMTST(EXP,LABL);
%compiles boolean expression EXP.
%If EXP has the same value as SWITCH then branch to LABL,
%otherwise fall through;
%REGS/IREGS are active registers for fall through,
%REGS1/IREGS1 for branch;
BEGIN SCALAR X;
WHILE EQCAR(EXP,'NULL) DO
<<SWITCH := NOT SWITCH; EXP := CADR EXP>>;
IF NOT ATOM EXP AND ATOM CAR EXP
AND (X := GET(CAR EXP,'COMTST))
THEN APPLY(X,LIST(EXP,LABL))
ELSE <<IF EXP = '(QUOTE T)
THEN IF SWITCH THEN !&ATTJMP LABL
ELSE FLAGG := T
ELSE <<!&COMVAL(EXP,1);
!&ATTACH LIST(IF SWITCH THEN '!*JUMPT ELSE '!*JUMPNIL,
CAR LABL);
!&ADDJMP CODELIST>>;
REGS1 := REGS; IREGS1 :=IREGS>>;
IF EQCAR(CAR CODELIST,'!*JUMPT)
THEN REGS := (1 . '(QUOTE NIL) . CDAR REGS) . CDR REGS
ELSE IF EQCAR(CAR CODELIST,'!*JUMPNIL)
THEN REGS1 := (1 . '(QUOTE NIL) . CDAR REGS1) . CDR REGS1
END;
COMMENT Specific Function Open Coding;
SYMBOLIC PROCEDURE !&COMANDOR(EXP,STATUS);
BEGIN SCALAR FN,LABL,IREGSL,REGSL;
FN := CAR EXP EQ 'AND;
LABL := !&GENLBL();
IF STATUS>1 THEN <<!&TSTANDOR(EXP,LABL);
REGS := !&RMERGE2(REGS,REGS1)>>
ELSE BEGIN
IF STATUS>0 THEN !&CLRREGS();
EXP := CDR EXP;
WHILE EXP DO
<<!&COMVAL(CAR EXP,IF CDR EXP THEN 1 ELSE STATUS);
%to allow for recursion on last entry;
IREGSL := IREGS . IREGSL; REGSL := REGS . REGSL;
IF CDR EXP THEN <<!&ATTACH LIST(IF FN THEN '!*JUMPNIL
ELSE '!*JUMPT,CAR LABL);
!&ADDJMP CODELIST>>;
EXP := CDR EXP>>;
IREGS := !&RMERGE IREGSL;
REGS := !&RMERGE REGSL;
END;
!&ATTLBL LABL
END;
SYMBOLIC PROCEDURE !&TSTANDOR(EXP,LABL);
BEGIN SCALAR FLG,FN,LAB2,REGSL,REGS1L,TAILP;
FLG := SWITCH;
SWITCH := NIL;
FN := CAR EXP EQ 'AND;
EXP := CDR EXP;
LAB2 := !&GENLBL();
!&CLRREGS();
WHILE EXP DO
<<SWITCH := NIL;
IF NULL CDR EXP AND FLG EQ FN
THEN <<IF FN THEN SWITCH := T;
!&COMTST(CAR EXP,LABL);
REGSL := REGS . REGSL;
REGS1L := REGS1 . REGS1L>>
ELSE <<IF NOT FN THEN SWITCH := T;
IF FLG EQ FN
THEN <<!&COMTST(CAR EXP,LAB2);
REGSL := REGS1 . REGSL;
REGS1L := REGS . REGS1L>>
ELSE <<!&COMTST(CAR EXP,LABL);
REGSL := REGS . REGSL;
REGS1L := REGS1 . REGS1L>>>>;
IF NULL TAILP
THEN <<CONDTAIL := NIL . CONDTAIL; TAILP := T>>;
EXP := CDR EXP>>;
!&ATTLBL LAB2;
REGS := IF FN THEN CAR REGSL ELSE !&RMERGE REGSL;
REGS1 := IF NULL FN THEN CAR REGS1L ELSE !&RMERGE REGS1L;
IF TAILP THEN CONDTAIL := CDR CONDTAIL;
SWITCH := FLG
END;
PUT('AND,'COMPFN,'!&COMANDOR);
PUT('OR,'COMPFN,'!&COMANDOR);
SYMBOLIC PROCEDURE !&COMCOND(EXP,STATUS);
%compiles conditional expressions;
%registers REGS and IREGS are set for dropping through,
%REGS1 and IREGS1 are set for a branch;
BEGIN SCALAR GOCHN,IREGS1,REGS1,FLAGG,SWITCH,LAB1,LAB2,
REGSL,IREGSL,TAILP;
EXP := CDR EXP;
LAB1 := !&GENLBL();
GOCHN := T;
IF STATUS>0 THEN !&CLRREGS();
FOR EACH X IN EXP DO
<<LAB2 := !&GENLBL();
SWITCH := NIL;
!&COMTST(CAR X,LAB2);
%update CONDTAIL;
IF NULL TAILP
THEN <<CONDTAIL := NIL . CONDTAIL; TAILP := T>>;
!&COMVAL(CADR X,STATUS); % Branch code;
%test if need jump to LAB1;
IF NOT EQCAR(CAR CODELIST,'!*JUMP)
THEN <<GOCHN := NIL; !&ATTJMP LAB1>>;
IREGSL := IREGS . IREGSL;
REGSL := REGS . REGSL;
REGS := REGS1; %restore register status for next iteration;
IREGS := IREGS1;
!&ATTLBL LAB2>>;
IF NULL FLAGG AND STATUS<2
THEN <<!&LREG1('(QUOTE NIL),STATUS);
IREGSL := IREGS . IREGSL;
REGSL := REGS . REGSL>>;
%missing ELSE clause;
IF NULL GOCHN THEN <<IREGS := !&RMERGE(IREGS . IREGSL);
REGS := !&RMERGE(REGS . REGSL)>>;
!&ATTLBL LAB1;
IF TAILP THEN CONDTAIL := CDR CONDTAIL
END;
SYMBOLIC PROCEDURE !&RMERGE U;
IF NULL U THEN NIL ELSE !&RMERGE1(CAR U,CDR U);
SYMBOLIC PROCEDURE !&RMERGE1(U,V);
IF NULL V THEN U
ELSE !&RMERGE1(!&RMERGE2(U,CAR V),CDR V);
SYMBOLIC PROCEDURE !&RMERGE2(U,V);
IF NULL U OR NULL V THEN NIL
ELSE (LAMBDA X;
IF X THEN (CAAR U . XN(CDAR U,CDR X))
. !&RMERGE2(CDR U,DELETE(X,V))
ELSE !&RMERGE2(CDR U,V))
ASSOC(CAAR U,V);
PUT('COND,'COMPFN,'!&COMCOND);
SYMBOLIC PROCEDURE !&COMCONS(EXP,STATUS);
IF NULL (EXP := CDR EXP) OR NULL CDR EXP OR CDDR EXP
THEN LPRIE "MISMATCH OF ARGUMENTS"
ELSE IF CADR EXP= '(QUOTE NIL)
THEN !&CALL('NCONS,!&COMLIS LIST CAR EXP,STATUS)
ELSE IF !&ANYREG(CADR EXP,NIL)
THEN !&CALL('CONS,!&COMLIS EXP,STATUS)
ELSE !&CALL('XCONS,REVERSIP !&COMLIS EXP,STATUS);
PUT('CONS,'COMPFN,'!&COMCONS);
SYMBOLIC PROCEDURE !&COMGO(EXP,STATUS);
IF STATUS>2
THEN <<!&ATTJMP !&GETLBL CADR EXP; SLST := NIL>>
ELSE LPRIE "INVALID GO STATEMENT";
PUT('GO,'COMPFN,'!&COMGO);
SYMBOLIC PROCEDURE !&COMLIST(EXP,STATUS);
%we only support explicit functions up to 5 registers here;
BEGIN SCALAR M,N,FN;
EXP := CDR EXP;
M := MIN(MAXNARGS,5);
N := LENGTH EXP;
IF N=0 THEN !&LREG1('(QUOTE NIL),STATUS)
ELSE IF N>M THEN !&COMVAL(!&COMLIST2 EXP,STATUS)
ELSE !&CALL(IF N=1 THEN 'NCONS
ELSE IF N=2 THEN 'LIST2
ELSE IF N=3 THEN 'LIST3
ELSE IF N=4 THEN 'LIST4 ELSE 'LIST5,
!&COMLIS EXP,STATUS)
END;
SYMBOLIC PROCEDURE LIST2(U,V); U . V . NIL;
SYMBOLIC PROCEDURE LIST3(U,V,W); U . V . W . NIL;
SYMBOLIC PROCEDURE LIST4(U,V,W,X); U . V . W . X . NIL;
SYMBOLIC PROCEDURE LIST5(U,V,W,X,Y); U . V . W . X . Y . NIL;
SYMBOLIC PROCEDURE !&COMLIST2 EXP;
BEGIN SCALAR L1,N;
N := MIN(MAXNARGS,5);
WHILE N>0 DO
<<L1 := CAR EXP . L1; EXP := CDR EXP; N := N-1>>;
RETURN LIST('NCONC,'LIST . REVERSIP L1,'LIST . EXP)
END;
PUT('LIST,'COMPFN,'!&COMLIST);
COMMENT an alternative definition for COMLIST;
%SYMBOLIC PROCEDURE !&COMLIST(EXP,STATUS);
% Map to sequence of CONS's;
% !&COMVAL(!&COMLIST1 CDR EXP,STATUS);
%SYMBOLIC PROCEDURE !&COMLIST1 EXP;
% IF NULL EXP THEN '(QUOTE NIL) ;
% ELSE LIST('CONS,CAR EXP,!&COMLIST1 CDR EXP);
SYMBOLIC PROCEDURE !&PAMAP(U,VARS);
IF EQCAR(CADDR U,'FUNCTION)
THEN (LAMBDA X; LIST(CAR U,!&PA1(CADR U,VARS),
MKQUOTE IF ATOM X THEN X ELSE !&PA1(X,VARS)))
CADR CADDR U
ELSE CAR U . !&PALIS(CDR U,VARS);
PUT('MAP,'PA1FN,'!&PAMAP);
PUT('MAPC,'PA1FN,'!&PAMAP);
SYMBOLIC PROCEDURE !&MAP(EXP,STATUS);
BEGIN SCALAR BODY,FN,LAB1,LAB2,SLST1,VAR,X;
BODY := CADR EXP; FN := CADDR EXP;
LAB1 := !&GENLBL(); LAB2 := !&GENLBL();
!&CLRREGS();
!&FRAME(VAR := GENSYM());
!&COMVAL(BODY,1);
REGS := LIST LIST(1,VAR);
!&ATTLBL LAB1;
!&ATTACH LIST('!*JUMPNIL,CAR LAB2);
!&ADDJMP CODELIST;
!&STORE(VAR,1);
X := IF CAR EXP EQ 'MAP THEN VAR ELSE LIST('CAR,VAR);
IF EQCAR(FN,'QUOTE) THEN FN := CADR FN;
SLST1 := SLST; %to allow for store in function body;
!&COMVAL(LIST(FN,X),3);
SLST := XN(SLST,SLST1);
!&COMVAL(LIST('CDR,VAR),1);
!&ATTJMP LAB1;
!&ATTLBL LAB2;
REGS := LIST LIST(1,MKQUOTE NIL);
END;
SYMBOLIC PROCEDURE XN(U,V);
IF NULL U THEN NIL
ELSE IF CAR U MEMBER V THEN CAR U . XN(CDR U,DELETE(CAR U,V))
ELSE XN(CDR U,V);
PUT('MAP,'COMPFN,'!&MAP);
PUT('MAPC,'COMPFN,'!&MAP);
SYMBOLIC PROCEDURE !&COMPROG(EXP,STATUS);
%compiles program blocks;
BEGIN SCALAR ALSTS,GOLIST,PG,PROGLIS,RETN; INTEGER I;
PROGLIS := CADR EXP;
EXP := CDDR EXP;
RETN := !&GENLBL();
PG := !&REMVARL PROGLIS; %protect prog variables;
FOR EACH X IN PROGLIS DO !&FRAME X;
ALSTS := !&FREEBIND(PROGLIS,NIL);
FOR EACH X IN PROGLIS DO
IF NOT NONLOCAL X THEN !&STORE(X,NIL);
FOR EACH X IN EXP DO
IF ATOM X THEN GOLIST := (X . !&GENLBL()) . GOLIST;
WHILE EXP DO
<<IF ATOM CAR EXP
THEN <<!&CLRREGS();
!&ATTLBL !&GETLBL CAR EXP;
REGS:= LIST(1 . NIL)>>
%since we do not know how we arrived here;
ELSE !&COMVAL(CAR EXP,IF STATUS>2 THEN 4 ELSE 3);
IF NULL CDR EXP AND STATUS<2
AND (ATOM CAR EXP OR NOT CAAR EXP MEMBER '(GO RETURN))
THEN EXP := LIST '(RETURN (QUOTE NIL))
ELSE EXP := CDR EXP>>;
!&ATTLBL RETN;
IF CDR !&FINDLBL RETN THEN REGS := LIST(1 . NIL);
!&FREERSTR(ALSTS,STATUS);
!&RSTVARL(PROGLIS,PG)
END;
PUT('PROG,'COMPFN,'!&COMPROG);
SYMBOLIC PROCEDURE !&REMVARL VARS;
FOR EACH X IN VARS COLLECT !&REMVAR X;
SYMBOLIC PROCEDURE !&REMVAR X;
%removes references to variable X from IREGS and REGS
%and protects SLST;
BEGIN
FOR EACH Y IN IREGS DO
IF X EQ CADR Y THEN <<!&STORE(CADR Y,CAR Y);
IREGS := DELETE(Y,IREGS)>>;
FOR EACH Y IN REGS DO
WHILE X MEMBER CDR Y DO RPLACD(Y,!&DELEQ(X,CDR Y));
RETURN !&PROTECT X
END;
SYMBOLIC PROCEDURE !&PROTECT U;
BEGIN SCALAR X;
IF (X := ATSOC(U,SLST)) THEN SLST := !&DELEQ(X,SLST);
RETURN X
END;
SYMBOLIC PROCEDURE !&RSTVARL(VARS,LST);
WHILE VARS DO
<<!&RSTVAR(CAR VARS,CAR LST); VARS := CDR VARS; LST := CDR LST>>;
SYMBOLIC PROCEDURE !&RSTVAR(VAR,VAL);
BEGIN
FOR EACH X IN IREGS DO
IF VAR EQ CADR X THEN <<!&STORE(CADR X,CAR X);
IREGS := DELETE(X,IREGS)>>;
FOR EACH X IN REGS DO
WHILE VAR MEMBER CDR X DO RPLACD(X,!&DELEQ(VAR,CDR X));
!&CLRSTR VAR;
!&UNPROTECT VAL
END;
SYMBOLIC PROCEDURE !&CLRSTR VAR;
%removes unneeded stores;
BEGIN SCALAR X;
IF CONDTAIL THEN RETURN NIL;
X := ATSOC(VAR,SLST);
IF NULL X THEN RETURN NIL;
STLST := !&DELEQ(CADR X,STLST);
SLST := !&DELEQ(X,SLST);
RPLACA(CADR X,'!*NOOP)
END;
SYMBOLIC PROCEDURE !&UNPROTECT VAL;
%restores VAL to SLST;
IF VAL THEN SLST := VAL . SLST;
SYMBOLIC PROCEDURE !&COMPROGN(EXP,STATUS);
BEGIN
EXP := CDR EXP;
WHILE CDR EXP DO
<<!&COMVAL(CAR EXP,IF STATUS<2 THEN 2 ELSE STATUS);
EXP := CDR EXP>>;
!&COMVAL(CAR EXP,STATUS)
END;
PUT('PROG2,'COMPFN,'!&COMPROGN);
PUT('PROGN,'COMPFN,'!&COMPROGN);
SYMBOLIC PROCEDURE !&COMRETURN(EXP,STATUS);
<<IF STATUS<4 OR NOT !&ANYREG(CADR EXP,NIL)
THEN !&LREG1(CAR !&COMLIS LIST CADR EXP,STATUS);
!&ATTJMP RETN>>;
PUT('RETURN,'COMPFN,'!&COMRETURN);
SYMBOLIC PROCEDURE !&COMSETQ(EXP,STATUS);
BEGIN SCALAR X;
EXP := CDR EXP;
IF STATUS>1 AND (NULL CADR EXP OR CADR EXP='(QUOTE NIL))
THEN !&STORE2(CAR EXP,NIL)
ELSE <<!&COMVAL(CADR EXP,1);
REGS := !&REMSETVAR(REGS,CAR EXP);
!&STORE2(CAR EXP,1);
IF X := !&RASSOC(CAR EXP,IREGS)
THEN IREGS := DELETE(X,IREGS);
REGS := (1 . CAR EXP . CDAR REGS) . CDR REGS>>
END;
SYMBOLIC PROCEDURE !&REMSETVAR(U,V);
IF NULL U THEN NIL
ELSE (CAAR U . !&REMS1(CDAR U,V)) . !&REMSETVAR(CDR U,V);
SYMBOLIC PROCEDURE !&REMS1(U,V);
IF NULL U THEN NIL
ELSE IF ATOM U
THEN IF U EQ V THEN !&REMS1(CDR U,V)
ELSE CAR U . !&REMS1(CDR U,V)
ELSE IF CAR U EQ 'QUOTE OR NOT V MEMBER FLATTEN CAR U
THEN CAR U . !&REMS1(CDR U,V)
ELSE !&REMS1(CDR U,V);
SYMBOLIC PROCEDURE !&STORE2(U,V);
BEGIN SCALAR VTYPE;
IF VTYPE := NONLOCAL U
THEN !&ATTACH LIST('!*STORE,V,LIST(VTYPE,U))
ELSE IF NOT ATSOC(U,STOMAP)
THEN !&ATTACH LIST('!*STORE,V,MKNONLOCAL U)
ELSE !&STORE(U,V);
END;
PUT('SETQ,'COMPFN,'!&COMSETQ);
COMMENT Specific Test Open Coding;
PUT('AND,'COMTST,'!&TSTANDOR);
PUT('OR,'COMTST,'!&TSTANDOR);
SYMBOLIC PROCEDURE !&CEQ(EXP,LABL);
BEGIN SCALAR U,V,W;
U := CADR EXP;
V := CADDR EXP;
IF U MEMBER CDAR REGS THEN W := !&CEQ1(V,U)
ELSE IF V MEMBER CDAR REGS THEN W := !&CEQ1(U,V)
ELSE IF !&ANYREG(V,NIL) THEN <<!&COMVAL(U,1);
W := !&LOCATE V>>
ELSE IF !&ANYREG(U,LIST V) THEN <<!&COMVAL(V,1);
W := !&LOCATE U>>
ELSE <<U := !&COMLIS CDR EXP; W := !&LOCATE CADR U>>;
!&ATTACH ((IF SWITCH THEN '!*JUMPE ELSE '!*JUMPN)
. CAR LABL . W);
IREGS1 := IREGS; REGS1 := REGS;
!&ADDJMP CODELIST
END;
SYMBOLIC PROCEDURE !&CEQ1(U,V);
IF !&ANYREG(U,LIST V) THEN !&LOCATE U
ELSE <<!&COMVAL(U,1); !&LOCATE V>>;
PUT('EQ,'COMTST,'!&CEQ);
COMMENT Support Functions;
SYMBOLIC PROCEDURE !&MEMLIS(U,V);
V AND (!&MEMB(U,CAR V) OR !&MEMLIS(U,CDR V));
SYMBOLIC PROCEDURE !&MEMB(U,V);
IF ATOM V THEN U EQ V ELSE !&MEMB(U,CADR V);
SYMBOLIC PROCEDURE !&RASSOC(U,V);
IF NULL V THEN NIL
ELSE IF U MEMBER CDAR V THEN CAR V
ELSE !&RASSOC(U,CDR V);
SYMBOLIC PROCEDURE !&REPASC(REG,U,V);
IF NULL V THEN LIST LIST(REG,U)
ELSE IF REG=CAAR V THEN LIST(REG,U) . CDR V
ELSE CAR V . !&REPASC(REG,U,CDR V);
SYMBOLIC PROCEDURE !&CLRREGS();
%store deferred values in IREGS;
WHILE IREGS DO <<!&STORE(CADAR IREGS,CAAR IREGS);
IREGS := CDR IREGS>>;
SYMBOLIC PROCEDURE !&GENLBL();
BEGIN SCALAR L;
L := GENSYM();
LBLIST := LIST L . LBLIST;
RETURN LIST L;
END;
SYMBOLIC PROCEDURE !&GETLBL LABL;
BEGIN SCALAR X;
X := ATSOC(LABL,GOLIST);
IF NULL X THEN LPRIE LIST(LABL," - MISSING LABEL -");
RETURN CDR X
END;
SYMBOLIC PROCEDURE !&FINDLBL LBLST;
ASSOC(CAR LBLST,LBLIST);
SYMBOLIC PROCEDURE !&RECHAIN(OLBL,NLBL);
% Fix OLBL to now point at NLBL;
BEGIN SCALAR X,Y,USES;
X := !&FINDLBL OLBL;
Y := !&FINDLBL NLBL;
RPLACA(OLBL,CAR NLBL); % FIX L VAR;
USES:=CDR X; % OLD USES;
RPLACD(X,NIL);
RPLACD(Y,APPEND(USES,CDR Y));
FOR EACH X IN USES DO RPLACA(CDR X,CAR NLBL)
END;
SYMBOLIC PROCEDURE !&MOVEUP U;
IF CAADR U EQ '!*JUMP
THEN <<JMPLIST:=!&DELEQ(CDR U,JMPLIST);
RPLACW(U,CDR U);
JMPLIST:=U . JMPLIST>>
ELSE RPLACW(U,CDR U);
SYMBOLIC PROCEDURE !&ATTLBL LBL;
IF CAAR CODELIST EQ '!*LBL THEN !&RECHAIN(LBL,CDAR CODELIST)
ELSE !&ATTACH ('!*LBL . LBL);
SYMBOLIC PROCEDURE !&ATTJMP LBL;
BEGIN
IF CAAR CODELIST EQ '!*LBL THEN
<<!&RECHAIN(CDAR CODELIST,LBL);
CODELIST := CDR CODELIST>>;
IF CAAR CODELIST EQ '!*JUMP THEN RETURN;
!&ATTACH ('!*JUMP . LBL);
!&ADDJMP CODELIST
END;
SYMBOLIC PROCEDURE !&ADDJMP CLIST;
BEGIN SCALAR X;
X := !&FINDLBL CDAR CLIST; RPLACD(X,CAR CLIST . CDR X);
JMPLIST := CLIST . JMPLIST
END;
SYMBOLIC PROCEDURE !&REMJMP CLIST;
BEGIN SCALAR X;
X := !&FINDLBL CDAR CLIST;
RPLACD(X,!&DELEQ(CAR CLIST,CDR X));
JMPLIST := !&DELEQ(CLIST,JMPLIST);
!&MOVEUP CLIST;
END;
SYMBOLIC PROCEDURE !&DELEQ(U,V);
IF NULL V THEN NIL
ELSE IF U EQ CAR V THEN CDR V
ELSE CAR V . !&DELEQ(U,CDR V);
SYMBOLIC PROCEDURE !&FRAME U;
% ALLOCATES SPACE FOR U IN FRAME;
BEGIN SCALAR Z;
STOMAP := LIST(U,Z := CADAR STOMAP+1) . STOMAP;
IF Z>CAR LLNGTH THEN RPLACA(LLNGTH,Z)
END;
SYMBOLIC PROCEDURE !&GETFRM U;
(LAMBDA X;
IF X THEN CDR X
ELSE LPRIE LIST("COMPILER ERROR: LOST VAR",U))
ATSOC(U,STOMAP);
SYMBOLIC PROCEDURE !&GETFFRM U;
BEGIN SCALAR X;
X := !&GETFRM U;
FREELST := X . FREELST;
RETURN X
END;
COMMENT Post Code Generation Fixups;
SYMBOLIC PROCEDURE !&FIXUPS;
BEGIN SCALAR FLAGG;
FOR EACH J IN SLST
DO <<STLST := !&DELEQ(CADR J,STLST); RPLACA(CADR J,'!*NOOP)>>;
!&FIXUP1();
IF FLAGG THEN <<IF NOT !*NOLINKR
AND CAAR CODELIST EQ '!*LBL
AND CAADR CODELIST EQ '!*LINKR
THEN RPLACA(CDR CODELIST,
LIST('!*LINK,CADADR CODELIST,
CADR CDADR CODELIST));
%removes unnecessary LINKR;
!&ATTACH('!*DEALLOC . LLNGTH);
!&ATTACH LIST '!*RETURN>>;
RETURN !&FIXUP2()
END;
SYMBOLIC PROCEDURE !&FIXUP1;
BEGIN SCALAR EJMPS,EJMPS1,P,Q;
IF NOT CAR CODELIST ='!*LBL . RETN THEN !&ATTLBL RETN;
CODELIST := CDR CODELIST;
IF NOT CAR CODELIST = '!*JUMP . RETN THEN !&ATTJMP RETN;
%find any common chains of code;
EJMPS := REVERSE JMPLIST;
WHILE EJMPS DO
BEGIN
P := CAR EJMPS; EJMPS := CDR EJMPS;
IF CAAR P EQ '!*JUMP
THEN <<EJMPS1 := EJMPS;
WHILE EJMPS1 DO
IF CAR P=CAAR EJMPS1 AND CADR P=CADAR EJMPS1
THEN <<!&REMJMP P;
!&FIXCHN(P,CDAR EJMPS1);
EJMPS1 := NIL>>
ELSE EJMPS1 := CDR EJMPS1>>
END;
%replace LINK by LINKR where appropriate;
EJMPS := JMPLIST;
IF NOT !*NOLINKR THEN WHILE EJMPS DO
BEGIN
P := CAR EJMPS; Q := CDR P; EJMPS := CDR EJMPS;
IF NOT CADAR P EQ CAR RETN THEN RETURN NIL
ELSE IF NOT CAAR P EQ '!*JUMP OR NOT CAAR Q EQ '!*LINK
THEN RETURN FLAGG := T;
RPLACW(CAR Q,'!*LINKR . CADAR Q . CADDAR Q . LLNGTH);
!&REMJMP P;
END ELSE FLAGG := T;
!&FIXFRM();
!&ATTLBL RETN
END;
SYMBOLIC PROCEDURE !&FINDBLK(U,LBL);
IF NULL CDR U THEN NIL
ELSE IF CAADR U EQ '!*LBL AND CAADDR U MEMBER '(!*LINKR !*JUMP)
THEN U
ELSE IF GET(CAADR U,'NEGJMP) AND CADADR U EQ LBL THEN U
ELSE !&FINDBLK(CDR U,LBL);
PUT('!*NOOP,'OPTFN,'!&MOVEUP);
PUT('!*LBL,'OPTFN,'!&LABOPT);
SYMBOLIC PROCEDURE !&LABOPT U;
BEGIN SCALAR Z;
IF CADAR U EQ CADADR U
THEN RETURN !&REMJMP CDR U %(JUMPx lab) (LAB lab);
ELSE IF CAADR U EQ '!*JUMP AND (Z := GET(CAADDR U,'NEGJMP))
AND CADAR U EQ CADR CADDR U
THEN RETURN <<Z := Z . CADADR U . CDDR CADDR U;
!&REMJMP CDR U;
!&REMJMP CDR U;
RPLACD(U,Z . CADR U . CDDR U);
!&ADDJMP CDR U;
T>> %(JUMPx lab1) (JUMP lab2) (LAB lab1);
ELSE RETURN NIL
END;
SYMBOLIC PROCEDURE !&FIXUP2;
%'peep-hole' optimization for various cases;
BEGIN SCALAR LABS,TLABS,X,Y,Z;
%local code fixes;
Z := CODELIST;
WHILE Z DO IF NOT (X := GET(CAAR Z,'OPTFN))
OR NOT APPLY(X,LIST Z)
THEN Z := CDR Z;
WHILE CODELIST DO
<<IF CAAR CODELIST EQ '!*LBL
THEN <<!&LABOPT CODELIST;
%since block transfers may cause new chains to emerge;
IF CDR (Z := !&FINDLBL CDAR CODELIST)
THEN <<Y := CAR CODELIST . Y;
IF NULL CDDR Z
AND CAADR Z MEMBER '(!*JUMP !*LINKR)
AND CAADR Y EQ '!*LOAD
AND !&NOLOADP(CDADR Y,
CDR ATSOC(CADR Z,JMPLIST))
THEN <<IF NOT !&NOLOADP(CDADR Y,CDR CODELIST)
THEN RPLACW(CDR CODELIST,CADR Y .
CADR CODELIST . CDDR CODELIST);
RPLACW(CDR Y,CDDR Y)>>
ELSE <<IF NULL CDDR Z AND CAADR CODELIST EQ '!*JUMP
AND GET(CAADR Z,'NEGJMP)
THEN LABS := (CADR Z . Y) . LABS;
IF CAADR CODELIST MEMBER '(!*JUMP !*LINKR)
THEN TLABS := (CADAR Y . Y) . TLABS>>>>>>
%case of (JUMPx lab) M1 ... Mn ... (LAB lab) M1 ... Mn
%where Mi do not affect reg 1;
ELSE IF GET(CAAR CODELIST,'NEGJMP)
AND (Z := ATSOC(CAR CODELIST,LABS))
THEN <<X := CAR CODELIST; CODELIST := CDR CODELIST;
Z := CDDR Z;
WHILE CAR Y=CAR Z AND (CAAR Y EQ '!*STORE
OR CAAR Y EQ '!*LOAD AND NOT(CADAR Y=1)) DO
<<CODELIST := CAR Y . CODELIST;
RPLACW(Z,CADR Z . CDDR Z);
Y := CDR Y>>;
CODELIST := X . CODELIST;
Y:= X . Y>>
ELSE IF CAAR CODELIST EQ '!*JUMP
AND (Z := ATSOC(CADAR CODELIST,TLABS))
AND (X := !&FINDBLK(CDR CODELIST,
IF CAAR Y EQ '!*LBL THEN CADAR Y
ELSE NIL))
THEN BEGIN SCALAR W;
IF NOT CAADR X EQ '!*LBL
THEN <<IF NOT CAAR X EQ '!*LBL
THEN X := CDR RPLACD(X,('!*LBL . !&GENLBL())
. CDR X);
W:= GET(CAADR X,'NEGJMP) . CADAR X . CDDADR X;
!&REMJMP CDR X;
RPLACD(X,W . CADR X . CDDR X);
!&ADDJMP CDR X>>
ELSE X := CDR X;
W := NIL;
REPEAT <<W := CAR Y . W; Y := CDR Y>> UNTIL Y EQ CDR Z;
RPLACD(X,NCONC(W,CDR X));
!&REMJMP CODELIST;
TLABS := NIL; %since code chains have changed;
CODELIST := NIL . CAR Y . CODELIST;
Y := CDR Y
END
ELSE Y := CAR CODELIST . Y;
CODELIST := CDR CODELIST>>;
RETURN Y
END;
SYMBOLIC PROCEDURE !&NOLOADP(ARGS,INSTRS);
%determines if a LOAD is not necessary in instruction stream;
ATOM CADR ARGS AND
(CAAR INSTRS EQ '!*LOAD AND CDAR INSTRS=ARGS
OR CAAR INSTRS EQ '!*STORE AND (CDAR INSTRS=ARGS
OR CADDAR INSTRS NEQ CADR ARGS
AND !&NOLOADP(ARGS,CDR INSTRS)));
SYMBOLIC PROCEDURE !&FIXCHN(U,V);
BEGIN SCALAR X;
WHILE CAR U=CAR V DO <<!&MOVEUP U; V := CDR V>>;
X := !&GENLBL();
IF CAAR V EQ '!*LBL THEN !&RECHAIN(X,CDAR V)
ELSE RPLACW(V,('!*LBL . X) . CAR V . CDR V);
IF CAAR U EQ '!*LBL
THEN <<!&RECHAIN(CDAR U,X);!&MOVEUP U>>;
IF CAAR U EQ '!*JUMP THEN RETURN;
RPLACW(U,('!*JUMP . X) . CAR U . CDR U);
!&ADDJMP U
END;
SYMBOLIC PROCEDURE !&FIXFRM;
BEGIN SCALAR HOLES,LST,X,Y,Z; INTEGER N;
IF NULL STLST THEN RETURN RPLACA(LLNGTH,0);
N := 1;
WHILE NOT(N>CAR LLNGTH) DO
<<Y:= NIL;
FOR EACH LST IN STLST DO
IF N = CADDR LST THEN Y := CDDR LST . Y;
FOR EACH LST IN FREELST DO
IF N=CAR LST THEN Y := LST . Y;
IF NULL Y THEN HOLES := N . HOLES ELSE Z := (N . Y) . Z;
N := N+1>>;
Y := Z;
IF CAAR Z<CAR LLNGTH THEN RPLACA(LLNGTH,CAAR Z);
WHILE HOLES DO <<
WHILE HOLES AND CAR HOLES>CAR LLNGTH
DO HOLES := CDR HOLES;
IF HOLES
THEN <<HOLES := REVERSIP HOLES;
FOR EACH X IN CDAR Z DO RPLACA(X,CAR HOLES);
RPLACA(LLNGTH,
IF NULL CDR Z OR CAR HOLES >CAADR Z
THEN CAR HOLES
ELSE CAADR Z);
HOLES := REVERSIP CDR HOLES;
Z := CDR Z>>>>;
%now see if we can map stack to registers;
IF FREELST OR NULL !®P CODELIST OR CAR LLNGTH>MAXNARGS-NARG
THEN RETURN;
N := IF NARG<3 THEN 3 ELSE NARG+1;
FOR EACH X IN STLST DO
RPLACW(X,LIST('!*LOAD,CADDR X+N,
IF NULL CADR X THEN '(QUOTE NIL)
ELSE LIST('!*REG,CADR X)));
WHILE Y DO
<<FOR EACH X IN CDAR Y DO
ATOM CAR X AND RPLACA(X,LIST('!*REG,CAR X+N));
Y := CDR Y>>;
RPLACA(LLNGTH,0)
END;
SYMBOLIC PROCEDURE !®P U;
%there is no test for LAMBIND/PROGBIND
%since FREELST tested explicitly in FIXFRM;
IF NULL CDR U THEN T
ELSE IF FLAGP(CAADR U,'LINK)
AND NOT(FLAGP!*!*(CADADR U,'TWOREG) OR CAR U =('!*JUMP . RETN))
THEN NIL
ELSE !®P CDR U;
SYMBOLIC PROCEDURE FLAGP!*!*(U,V);
ATOM U AND NOT NUMBERP U AND FLAGP(U,V);
FLAG('(!*LINK !*LINKL !*LINKR),'LINK);
PUT('!*JUMPN,'NEGJMP,'!*JUMPE);
PUT('!*JUMPE,'NEGJMP,'!*JUMPN);
PUT('!*JUMPNIL,'NEGJMP,'!*JUMPT);
PUT('!*JUMPT,'NEGJMP,'!*JUMPNIL);